package models;
/**
 * Klasa sprawdzajaca uklady.
 */
public final class SprawdzUklad {
    /**
     * Stala przechowujaca maksymalna ilosc kart jednego gracza.
     */
    private static final int ILOSC_KART = 5;
    /**
     * Liczba takich samych kart wymagana do trojki.
     */
    private static final int TROJKA = 3;
    /**
     * Stala przechowujaca kod asa.
     */
    private static final int AS = 14;
    /**
     * Stala przechowujaca kod dwoch par.
     */
    private static final int DWOJKA = 2;
    /**
     * Stala przechowujaca kod karety.
     */
    private static final int CZWORKA = 4;

    /**
     * Indeks najslabszej karty.
     */
    private static final int NAJSLABSZA_KARTA = 0;
    /**
     * Indeks najsilniejszej karty.
     */
    private static final int NAJSILNIEJSZA_KARTA = 4;
    /**
     * Indeks drugiej karty.
     */
    private static final int DRUGA_KARTA = 1;
    /**
     * Indeks trzeciej karty.
     */
    private static final int TRZECIA_KARTA = 2;
    /**
     * Indeks czwartej karty.
     */
    private static final int CZWARTA_KARTA = 3;
    /**
     * Stala przechowujaca wartosc pokera.
     */
    private static final int POKER = 8;
    /**
     * Stala przechowujaca wartosc karety.
     */
    private static final int KARETA = 7;
    /**
     * Stala przechowujaca wartosc fulla.
     */
    private static final int FULL = 6;
    /**
     * Stala przechowujaca wartosc koloru.
     */
    private static final int KOLOR = 5;
    /**
     * Stala przechowujaca wartosc strita.
     */
    private static final int STRIT = 4;
    /**
     * Metoda sprawdzajaca czy w ukladzie znajduje sie n takich samych kart.
     * 
     * @param karty tablica kart do sprwdzenia
     * @param n ilosc kart
     * @return true jesli w ukladzie znajduje sie n takich samych kart,
     * false w przeciwnym wypadku.
     */
    private static boolean czyNKart(final Karta[] karty, final int n) {
        Karta tmp = karty[0];
        int ile = 1;
        for (int i = 1; i < ILOSC_KART; i++) {
            if (tmp.compareTo(karty[i]) == 0) {
                ile++;
            } else {
                tmp = karty[i];
                if (ile >= n) {
                    return true;
                }
                ile = 1;
            }
        }
        return ile >= n; 
    }
    /**
     * Metoda sprawdzajaca czy uklad jest kolorem.
     * 
     * @param karty karty do sprawdzenia
     * @return true jesli uklad jest kolorem, false w przeciwnym wypadku
     */
    private static boolean czyKolor(final Karta[] karty) {
        int kolor = karty[0].pobierzKodKoloru();
        for (int i = 1; i < ILOSC_KART; i++) {
            if (kolor != karty[i].pobierzKodKoloru()) {
                return false;
            }
        }
        return true;
    }
    /**
     * Metoda sprawdzajaca czy uklad to dwie pary.
     * 
     * @param karty karty do sprawdzenia
     * @return true jesli uklad to dwie pary, false w przeciwnym wypadku
     */
    private static boolean czyDwiePary(final Karta[] karty) {
        int ilePar = 0;
        for (int i = 1; i < ILOSC_KART; i++) {
            if (karty[i].compareTo(karty[i - 1]) == 0) {
                ilePar++;
                i++;
            }
        }
        return ilePar == 2;
    }
    /**
     * Metoda sprawdzajaca czy uklad to full.
     * 
     * @param karty karty do sprawdzenia
     * @return true jesli uklad to full, false w przeciwnym wypadku
     */
    private static boolean czyFull(final Karta[] karty) {
        return czyDwiePary(karty) && czyNKart(karty, TROJKA);
    }
    /**
     * Metoda sprawdzajca czy uklad to strit.
     * 
     * @param karty karty do sprawdzenia
     * @return true jesli uklad to strit, false w przeciwnym wypadku
     */
    private static boolean czyStrit(final Karta[] karty) {
        if (karty[0].pobierzKodFigury() == 2 
                && karty[NAJSILNIEJSZA_KARTA].pobierzKodFigury() == AS) { 
            for (int i = 0; i < ILOSC_KART - 1; i++) {
                if (karty[i].pobierzKodFigury() 
                        != karty[0].pobierzKodFigury() + i) {
                    return false;
                }
            }
            return true;  
        }
        
        for (int i = 0; i < ILOSC_KART; i++) {
            if (karty[i].pobierzKodFigury() 
                    != karty[0].pobierzKodFigury() + i) {
                return false;
            }
        }
        return true;  

        
    }
    /**
     * Metoda sprawdzajaca czy uklad to poker.
     * 
     * @param karty uklad do sprawdzenia
     * @return true jesli uklad jest pokerem, falsz w przeciwnym wypadku 
     */
    private static boolean czyPoker(final Karta[] karty) {
        return czyStrit(karty) && czyKolor(karty);
    }
    
    /**
     * Metoda sprawdzajaca ktora para jest silniejsza.
     * 
     * @param g1 karty pierwszego gracza
     * @param g2 karty drugiego gracza
     * @return liczbe mniejsza od 0 jesli g1 ma silniejsza pare, 
     * liczbe wieksza od zera jesli g2 ma silniejsza pare, 
     * 0 jesli nie ma rozstrzygniecia. 
     */
    private static int para2razy(final Karta[] g1, final Karta[] g2) {
        Karta g1para;
        Karta g1k1;
        Karta g1k2;
        Karta g1k3;
        Karta g2para;
        Karta g2k1;
        Karta g2k2;
        Karta g2k3;
         
        if (g1[0].compareTo(g1[1]) == 0) {
            g1para = g1[0];
            g1k1 = g1[NAJSILNIEJSZA_KARTA];
            g1k2 = g1[CZWARTA_KARTA];
            g1k3 = g1[TRZECIA_KARTA];
        } else {
            if (g1[1].compareTo(g1[TRZECIA_KARTA]) == 0) {
                g1para = g1[1];
                g1k1 = g1[NAJSILNIEJSZA_KARTA];
                g1k2 = g1[CZWARTA_KARTA];
                g1k3 = g1[NAJSLABSZA_KARTA];
            } else {
                if (g1[2].compareTo(g1[CZWARTA_KARTA]) == 0) {
                    g1para = g1[TRZECIA_KARTA];
                    g1k1 = g1[NAJSILNIEJSZA_KARTA];
                    g1k2 = g1[DRUGA_KARTA];
                    g1k3 = g1[NAJSLABSZA_KARTA];
                } else {
                    g1para = g1[NAJSILNIEJSZA_KARTA];
                    g1k1 = g1[TRZECIA_KARTA];
                    g1k2 = g1[DRUGA_KARTA];
                    g1k3 = g1[NAJSLABSZA_KARTA];                 
                }
            }
        }
        if (g2[0].compareTo(g2[DRUGA_KARTA]) == 0) {
            g2para = g2[0];
            g2k1 = g2[NAJSILNIEJSZA_KARTA];
            g2k2 = g2[CZWARTA_KARTA];
            g2k3 = g2[TRZECIA_KARTA];
        } else {
            if (g2[1].compareTo(g2[TRZECIA_KARTA]) == 0) {
                g2para = g2[DRUGA_KARTA];
                g2k1 = g2[NAJSILNIEJSZA_KARTA];
                g2k2 = g2[CZWARTA_KARTA];
                g2k3 = g2[NAJSLABSZA_KARTA];
            } else {
                if (g2[2].compareTo(g2[CZWARTA_KARTA]) == 0) {
                    g2para = g2[TRZECIA_KARTA];
                    g2k1 = g2[NAJSILNIEJSZA_KARTA];
                    g2k2 = g2[DRUGA_KARTA];
                    g2k3 = g2[NAJSLABSZA_KARTA];
                } else {
                    g2para = g2[NAJSILNIEJSZA_KARTA];
                    g2k1 = g2[TRZECIA_KARTA];
                    g2k2 = g2[DRUGA_KARTA];
                    g2k3 = g2[NAJSLABSZA_KARTA];                 
                }
            }
        }
         
        int wynik = g1para.compareTo(g2para);
         
        if (wynik != 0) {
            return wynik;
        } else {
            wynik = g1k1.compareTo(g2k1);
            if (wynik != 0) {
                return wynik;
            } else {
                wynik = g1k2.compareTo(g2k2);
                if (wynik != 0) {
                    return wynik;
                } else {
                    return g1k3.compareTo(g2k3);
                }
            }
        }
    }
    /**
     * Metoda porownujaca dwie najwyzsze karty.
     * 
     * @param g1 karty pierwszego gracza 
     * @param g2 karty drugiego gracza
     * @return liczba wieksza od 0 jesli gracz g1 ma silniejszy uklad,
     * liczba mniejsza od 0 jesli gracz g2 ma silniejszy uklad.
     * 0 jesli uklady sa rowne.
     */
    private static int najwyzszaKarta2razy(final Karta[] g1, final Karta[] g2) {
        for (int i = NAJSILNIEJSZA_KARTA; i >= 0; i--) {
            if (g1[i].compareTo(g2[i]) > 0) {
                return 1;
            } else {
                if (g1[i].compareTo(g2[i]) < 0) {
                    return -1;
                }
            }
                    
        }
        return 0;
    }
    /**
     * Metoda porownujaca dwie trojki.
     * 
     * @param g1 karty pierwszego gracza 
     * @param g2 karty drugiego gracza
     * @return liczba wieksza od 0 jesli gracz g1 ma silniejszy uklad,
     * liczba mniejsza od 0 jesli gracz g2 ma silniejszy uklad.
     * 0 jesli uklady sa rowne.
     */
    private static int trojka2razy(final Karta[] g1, final Karta[] g2) {
        return g1[2].compareTo(g2[2]);
    }
    /**
     * Metoda porownujaca dwie pary.
     * 
     * @param g1 karty pierwszego gracza 
     * @param g2 karty drugiego gracza
     * @return liczba wieksza od 0 jesli gracz g1 ma silniejszy uklad,
     * liczba mniejsza od 0 jesli gracz g2 ma silniejszy uklad.
     * 0 jesli uklady sa rowne.
     */
    private static int dwiePary2razy(final Karta[] g1, final Karta[] g2) {
        Karta g1para1;
        Karta g1para2;
        Karta g1kicker;
        Karta g2para1;
        Karta g2para2;
        Karta g2kicker;
        
        if (g1[1].compareTo(g1[TRZECIA_KARTA]) == 0) {
            g1kicker = g1[NAJSLABSZA_KARTA];
            g1para1 = g1[NAJSILNIEJSZA_KARTA];
            g1para2 = g1[TRZECIA_KARTA];
        } else {
            if (g1[2].compareTo(g1[CZWARTA_KARTA]) == 0) {
                g1kicker = g1[NAJSILNIEJSZA_KARTA];
                g1para1 = g1[TRZECIA_KARTA];
                g1para2 = g1[DRUGA_KARTA];
            } else {
                g1kicker = g1[TRZECIA_KARTA];
                g1para1 = g1[NAJSILNIEJSZA_KARTA];
                g1para2 = g1[NAJSLABSZA_KARTA];
            }
        }
        if (g2[1].compareTo(g2[TRZECIA_KARTA]) == 0) {
            g2kicker = g2[NAJSLABSZA_KARTA];
            g2para1 = g2[NAJSILNIEJSZA_KARTA];
            g2para2 = g2[TRZECIA_KARTA];
        } else {
            if (g2[2].compareTo(g2[CZWARTA_KARTA]) == 0) {
                g2kicker = g2[NAJSILNIEJSZA_KARTA];
                g2para1 = g2[TRZECIA_KARTA];
                g2para2 = g2[DRUGA_KARTA];
            } else {
                g2kicker = g2[TRZECIA_KARTA];
                g2para1 = g2[NAJSILNIEJSZA_KARTA];
                g2para2 = g2[NAJSLABSZA_KARTA];
            }
        }
        int wynik = g1para1.compareTo(g2para1);
        if (wynik != 0) {
            return wynik;
        } else {
            wynik = g1para2.compareTo(g2para2);
            if (wynik != 0) {
                return wynik;
            } else {
                return g1kicker.compareTo(g2kicker);
            }
        }   
    }
    /**
     * Metoda porownujaca dwia strity.
     * 
     * @param g1 karty pierwszego gracza 
     * @param g2 karty drugiego gracza
     * @return liczba wieksza od 0 jesli gracz g1 ma silniejszy uklad,
     * liczba mniejsza od 0 jesli gracz g2 ma silniejszy uklad.
     * 0 jesli uklady sa rowne.
     */
    private static int strit2razy(final Karta[] g1, final Karta[] g2) {
        return g1[CZWARTA_KARTA].compareTo(g2[CZWARTA_KARTA]);
    }
    /**
     * Metoda zwracajace nazwe ukladu posiadanego przez gracza.
     * 
     * @param karty uklad posiadany przez gracza 
     * @return nazwa ukladu
     */
    public static String jakiUklad(final Karta[] karty) {
        if (czyPoker(karty)) {
            return "Poker";
        } 
        if (czyNKart(karty, CZWORKA)) {
            return "Kareta";
        }
        if (czyFull(karty)) {
            return "Full";
        }
        if (czyKolor(karty)) {
            return "Kolor";
        }
        if (czyStrit(karty)) {
            return "Strit";
        }
        if (czyNKart(karty, TROJKA)) {
            return "Trojka";
        }
        if (czyDwiePary(karty)) {
            return "Dwie pary";
        }
        if (czyNKart(karty, DWOJKA)) {
            return "Para";
        }
        return "najwyzsza karta " + karty[NAJSILNIEJSZA_KARTA];
    }
    /**
     * Metoda zwracajaca wartosc ukladu.
     * 
     * @param karty uklad do sprawdzenia
     * @return wartosc ukladu
     */
    public static int wartosciUkladu(final Karta[] karty) {
        if (czyPoker(karty)) {
            return POKER;
        }
        if (czyNKart(karty, CZWORKA)) {
            return KARETA;
        }
        if (czyFull(karty)) {
            return FULL;
        }
        if (czyKolor(karty)) {
            return KOLOR;
        }
        if (czyStrit(karty)) {
            return STRIT;
        }
        if (czyNKart(karty, TROJKA)) {
            return TROJKA;
        }
        if (czyDwiePary(karty)) {
            return 2;
        }
        if (czyNKart(karty, DWOJKA)) {
            return 1;
        }
        return 0;
    }
    /**
     * Metoda porownujaca dwa takie same uklady.
     * 
     * @param g1 karty pierwszego gracza 
     * @param g2 karty drugiego gracza
     * @param uklad wartosc ukladu
     * @return liczba wieksza od 0 jesli gracz g1 ma silniejszy uklad,
     * liczba mniejsza od 0 jesli gracz g2 ma silniejszy uklad.
     * 0 jesli uklady sa rowne.
     */
    public static int porownajTeSameUklady(final Karta[] g1, 
            final Karta[] g2, final int uklad) {
        switch(uklad) {
        default : return najwyzszaKarta2razy(g1, g2);
        case 1 : return para2razy(g1, g2);
        case DWOJKA : return dwiePary2razy(g1, g2);
        case TROJKA : return trojka2razy(g1, g2);
        case STRIT : return strit2razy(g1, g2);
        case FULL : return trojka2razy(g1, g2);
        case KARETA : return trojka2razy(g1, g2);
        case POKER : return strit2razy(g1, g2);
        }
    }
}